package com.wenlin.myproduction.widget;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.Nullable;

import com.wenlin.myproduction.BuildConfig;
import com.wenlin.myproduction.R;
import com.wenlin.myproduction.bean.LabelBean;

import java.util.ArrayList;
import java.util.List;

/**
 * @author cwl
 * @desc 标签组控件
 * @Email 377979485@qq.com
 * @time 2023/10/17/017 18:42
 */
public class LabelsView extends View {
    private static final int ANIM_DURATION = 200;
    private final float marginBetweenHor = dpToPx(15f);
    private final float minScrollDistance = dpToPx(10);//大致上弄个值
    private float labelHeight = dpToPx(23);
    private final float maxAnimFactor = labelHeight / 4f;//最大动画因子，即标签放大时向四周扩张比正常大小增加的距离
    private float round = labelHeight / 2;//圆角矩形的半径
    private float paddingHor = dpToPx(9.5f);//圆角矩形与文字的水平距离
    private float marginBetweenVer = dpToPx(12f);//正常标签的竖直距离
    private int viewWidth;//控件宽度：固定水平边距为16dp，两边就是32dp
    private int defaultShowRows = 2;//默认显示行数，超过行数的标签不显示，并显示展开按钮
    private int viewHeight;//控件高度：包含标签放大时的距离
    private Bitmap bitmapOpen, bitmapClose;//展开或者收起按钮的位图
    private List<LabelBean> list, listShow;//原始数据集、显示数据集
    private Paint paint, paintBitmap;//画笔，位图画笔
    private Rect rect;//计算文字宽高的矩形
    private String label;//标签文本
    private TextPaint textPaint, textPaintSelected;//正常显示的文字画笔、选中时的文字画笔
    private ValueAnimator valueAnimator;//值动画执行者
    private boolean canSelect;//是否可以选中标签，可以只显示，也可以选中
    private boolean open;//是否全部展开
    private boolean showBtn;//是否显示展开或收起按钮
    private boolean needOneRowMoreToShowBtn;//是否需要更多一行去显示按钮
    private float btnStartX, btnStartY;//按钮起始坐标
    private float lastX, lastY;//手指上次点击的坐标
    private float valueFactor;//动画执行因子
    private int maxRow;//最大行数
    private int row;//行数
    private int startX;//起始X坐标，用来计算一行放几个标签用的
    private long lastTimeClick;//防连点用的，记录上一次抬起手指的时间戳
    private OnClickListener onClickListener;//点击事件

    public LabelsView(Context context) {
        this(context, null);
    }

    public LabelsView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    //region 公共方法

    /**
     * 设置成未选中状态，带动画
     *
     * @param labelBean 标签
     */
    public void setUnSelected(LabelBean labelBean) {
        for (int i = 0; i < list.size(); i++) {
            if (labelBean.getId() == list.get(i).getId()) {
                list.get(i).setSelected(false);
                break;
            }
        }
        handleData();
        invalidate();
    }

    /**
     * 重置目标标签为原始状态，主要是没动画
     *
     * @param target 标签
     */
    public void resetTargetLabel(LabelBean target) {
        for (int i = 0; i < list.size(); i++) {
            if (target.getId() == list.get(i).getId()) {
                list.get(i).setSelected(false);
                list.get(i).setAnimFactor(0);
                list.get(i).setOldAnimFactor(0);
                break;
            }
        }
        handleData();
        invalidate();
    }

    /**
     * 设置数据集
     *
     * @param list            原始数据集
     * @param defaultShowRows 默认显示行数
     * @param canSelect       是否可以选中
     * @param listener        点击事件监听器
     */
    public void setLabels(List<LabelBean> list, int defaultShowRows, boolean canSelect, OnClickListener listener) {
        this.canSelect = canSelect;
        if (!canSelect) {
            if (list != null && list.size() > 0) {
                for (LabelBean temp :
                        list) {
                    temp.setName(temp.getName() + " (" + temp.getNums() + ")");
                }
            }
        }
        resetWithCanSelectOrNot();
        setDefaultShowRows(defaultShowRows);
        this.list = list;
        this.onClickListener = listener;
        showBtn = false;
        handleData();
        invalidate();
    }
    //endregion

    //region 数据处理

    /**
     * 设置默认显示行数
     *
     * @param defaultShowRows 默认显示行数
     */
    private void setDefaultShowRows(int defaultShowRows) {
        this.defaultShowRows = defaultShowRows;
        setHeight(false);
    }

    /**
     * 根据是否可以选中，重置相关参数
     */
    private void resetWithCanSelectOrNot() {
        textPaint.setTextSize(dpToPx(canSelect ? 16 : 14));
        textPaintSelected.setTextSize(dpToPx(canSelect ? 16 : 14));
        labelHeight = dpToPx(canSelect ? 27 : 23);
        round = labelHeight / 2;
        paddingHor = dpToPx(canSelect ? 10.5f : 12.5f);
        marginBetweenVer = dpToPx(canSelect ? 15 : 12f);
    }

    /**
     * 设置高度
     *
     * @param showAll 是否显示所有标签
     */
    private void setHeight(boolean showAll) {
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
        viewWidth = (int) (dpToPx(getResources().getConfiguration().screenWidthDp - 32));//cwl 2023/10/20/020 9:43:固定左边距和右边距都是16dp
//        viewWidth = (int) (dpToPx(getResources().getConfiguration().screenWidthDp)) - (params != null ? params.leftMargin : 0) - (params != null ? params.rightMargin : 0) - getPaddingLeft() - getPaddingRight();
        if (showAll) {
            viewHeight = (int) (labelHeight * (maxRow + 1 + (needOneRowMoreToShowBtn ? 1 : 0)) + marginBetweenVer * ((maxRow + 1 + (needOneRowMoreToShowBtn ? 1 : 0)) - 1) + labelHeight / 2f);
        } else {
            viewHeight = (int) (labelHeight * defaultShowRows + marginBetweenVer * (defaultShowRows - 1) + labelHeight / 2f);
        }
        requestLayout();
    }

    /**
     * 处理数据集，主要是计算每个标签的位置
     */
    private void handleData() {
        //计算并赋值
        row = 0;
        startX = (int) (marginBetweenHor / 2f);
        maxRow = 0;
        //所有标签
        for (int i = 0; i < list.size(); i++) {
            LabelBean bean = list.get(i);
            label = bean.getName();
            if (label != null && label.length() > 0) {
                textPaint.getTextBounds(label, 0, label.length(), rect);
                if (startX + paddingHor * 2 + rect.width() + labelHeight / 4f > viewWidth) {//如果下一个item放不下就跳行
                    row++;
                    startX = (int) (marginBetweenHor / 2f);
                }
                bean.setStartX(startX);
                bean.setStartY(row * (labelHeight + marginBetweenVer) + labelHeight / 4f);
                bean.setWidth(paddingHor * 2 + rect.width());
                bean.setHeight(labelHeight);
                startX += paddingHor * 2 + rect.width() + marginBetweenHor;
            }
            //处理颜色
            if (bean.getColour().startsWith("#") && bean.getColour().length() == 7) {//给的颜色如果是“#123456”这种格式的，需要加上不透明度FF，变成“#FF123456”这种格式
                bean.setColour("#FF" + bean.getColour().substring(1));
            }
            if (maxRow < row) maxRow = row;
        }
//        LogU.v("maxRow=" + maxRow);
        //筛选前三行标签
        listShow = new ArrayList<>();
        //找到未展开时显示的最后的一个item的位置
        int lastItemInRowShow = list.size() - 1;
        needOneRowMoreToShowBtn = false;
        if (!open) {
            for (int i = list.size() - 1; i >= 0; i--) {
                LabelBean bean = list.get(i);
                if (bean.getStartY() > (defaultShowRows - 1) * (labelHeight + marginBetweenVer) + labelHeight / 4f && !showBtn) {
                    showBtn = true;
                }
                if (bean.getStartY() == (defaultShowRows - 1) * (labelHeight + marginBetweenVer) + labelHeight / 4f) {
                    lastItemInRowShow = i;
//                    LogU.v("找到最后一个显示的item，脚标= " + lastItemInRowShow);
                    //如果这个item画完，按钮画不下，则往小再取一个值
                    if (bean.getStartX() + bean.getWidth() + marginBetweenHor > viewWidth - bitmapOpen.getWidth()) {
                        lastItemInRowShow--;
//                        LogU.v("加上btn，一行画不下，往前找一个item");
                    }
                    btnStartX = list.get(lastItemInRowShow).getStartX() + list.get(lastItemInRowShow).getWidth() + marginBetweenHor;
                    btnStartY = list.get(lastItemInRowShow).getStartY();
                    break;
                }
            }
        } else {
            if (list.get(lastItemInRowShow).getStartX() + list.get(lastItemInRowShow).getWidth() + marginBetweenHor > viewWidth - bitmapOpen.getWidth()) {
                needOneRowMoreToShowBtn = true;
                btnStartX = 0;
                btnStartY = list.get(lastItemInRowShow).getStartY() + labelHeight + marginBetweenVer;
//                LogU.v("另起一行画btn");
            } else {
                btnStartX = list.get(lastItemInRowShow).getStartX() + list.get(lastItemInRowShow).getWidth() + marginBetweenHor;
                btnStartY = list.get(lastItemInRowShow).getStartY();
//                LogU.v("直接在最后一行画btn");
            }
        }
        if (showBtn && !open) {
            listShow = list.subList(0, lastItemInRowShow + 1);//包前不包后
        } else {
            listShow = list;
        }
        if (maxRow < defaultShowRows) {//举个例子：默认显示2行，但是标签只有一行，则重新设置高度
            setHeight(true);
        }
    }

    /**
     * 处理数据中动画相关的值
     */
    private void handleDataWithAnim() {
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                LabelBean bean = list.get(i);
                if (bean.isSelected()) {//选中，放大动画
                    if (bean.getOldAnimFactor() < maxAnimFactor) {
                        bean.setAnimFactor(Math.min(bean.getOldAnimFactor() + valueFactor, maxAnimFactor));
                        if (bean.getAnimFactor() == maxAnimFactor)
                            bean.setOldAnimFactor(maxAnimFactor);
                    }
                } else {//取消选中，缩小动画
                    if (bean.getOldAnimFactor() > 0) {
                        bean.setAnimFactor(Math.max(bean.getOldAnimFactor() - valueFactor, 0));
                        if (bean.getAnimFactor() == 0) bean.setOldAnimFactor(0);
                    }
                }
            }
        }
    }
    //endregion

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        canvas.drawColor(Color.GRAY);
        //辅助线，找btn的位置
//        canvas.drawLine(0, btnStartY, getWidth(), btnStartY, paint);
//        canvas.drawLine(btnStartX, 0, btnStartX, getHeight(), paint);
        if (listShow != null && listShow.size() > 0) {
            for (int i = 0; i < listShow.size(); i++) {
                LabelBean bean = listShow.get(i);
                label = bean.getName();
                if (label != null && label.length() > 0) {
                    //画一个白色的圆角矩形背景，防止背景颜色串色，毕竟圆角背景是半透明的
                    paint.setColor(Color.WHITE);
                    canvas.drawRoundRect(bean.getStartX(),
                            bean.getStartY(),
                            bean.getStartX() + bean.getWidth(),
                            bean.getStartY() + bean.getHeight(),
                            round, round, paint);
                    //画圆角矩形背景
                    paint.setColor(bean.isSelected() || bean.getAnimFactor() > 0 ? Color.parseColor(bean.getColour()) : Color.parseColor(bean.getColour().replace("#FF", "#40")));
                    canvas.drawRoundRect(bean.getStartX() - bean.getAnimFactor(),
                            bean.getStartY() - bean.getAnimFactor(),
                            bean.getStartX() + bean.getWidth() + bean.getAnimFactor(),
                            bean.getStartY() + bean.getHeight() + bean.getAnimFactor(),
                            round + bean.getAnimFactor(), round + bean.getAnimFactor(), paint);
                    //画字
                    if (bean.isSelected()) {//选中时画白色粗字
                        textPaintSelected.getTextBounds(label, 0, label.length(), rect);
                        canvas.drawText(label,
                                bean.getStartX() + paddingHor,
                                bean.getStartY() + bean.getHeight() / 2f - (rect.bottom + rect.top) / 2f,
                                textPaintSelected);
                    } else {//未选中时画彩字
                        textPaint.getTextBounds(label, 0, label.length(), rect);
                        textPaint.setColor(Color.parseColor(bean.getColour()));
                        canvas.drawText(label,
                                bean.getStartX() + paddingHor,
                                bean.getStartY() + bean.getHeight() / 2f - (rect.bottom + rect.top) / 2f,
                                textPaint);
                    }
                }
            }
            //画按钮
            if (showBtn) {
                if (!open) {
                    canvas.drawBitmap(bitmapOpen, btnStartX, btnStartY, paintBitmap);
                } else {
                    canvas.drawBitmap(bitmapClose, btnStartX, btnStartY, paintBitmap);
                }
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://按下手指记录x坐标
                lastX = x;
                lastY = y;
                return true;
            case MotionEvent.ACTION_UP://手指抬起时
                float dx = x - lastX;
                float dy = y - lastY;
                if (System.currentTimeMillis() - lastTimeClick < ANIM_DURATION) return true;
                lastTimeClick = System.currentTimeMillis();
                if (Math.sqrt(dx * dx + dy * dy) < minScrollDistance) {//滑动距离未超过一定值，则视为点击
                    if (showBtn && x > btnStartX && x < btnStartX + labelHeight
                            && y > btnStartY && y < btnStartY + labelHeight) {//点击了展开或者收起按钮
                        open = !open;
                        handleData();
                        setHeight(open);
                        invalidate();
                    } else if (canSelect) {//可点击
                        for (int i = 0; i < list.size(); i++) {//点击了标签
                            LabelBean bean = list.get(i);
                            if (x > bean.getStartX() - bean.getAnimFactor() && x < bean.getStartX() + bean.getWidth() + bean.getAnimFactor()
                                    && y > bean.getStartY() - bean.getAnimFactor() && y < bean.getStartY() + bean.getHeight() + bean.getAnimFactor()) {
                                boolean selected = !bean.isSelected();
                                bean.setSelected(selected);
                                if (onClickListener != null) onClickListener.onClickItem(bean);
                                startAnim();
                                break;
                            }
                        }
                    }
                    performClick();
                }
                return true;
            default:
        }
        return super.onTouchEvent(event);
    }

    //region 初始化及非核心重写方法

    /**
     * 初始化
     */
    private void init() {
        //画笔
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        //位图画笔
        paintBitmap = new Paint();
        paintBitmap.setAntiAlias(true);
        paintBitmap.setStyle(Paint.Style.FILL_AND_STROKE);
        //正常显示的标签文本画笔
        textPaint = new TextPaint();
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(dpToPx(canSelect ? 16 : 14));
        textPaint.setFakeBoldText(true);
        //选中时的标签文本画笔
        textPaintSelected = new TextPaint();
        textPaintSelected.setAntiAlias(true);
        textPaintSelected.setTextSize(dpToPx(canSelect ? 16 : 14));
        textPaintSelected.setColor(Color.WHITE);
        textPaintSelected.setFakeBoldText(true);
        //位图
        bitmapOpen = BitmapFactory.decodeResource(getResources(), R.mipmap.common_icon_gray_arrow_down_with_gray_circle);
        bitmapClose = BitmapFactory.decodeResource(getResources(), R.mipmap.common_icon_gray_arrow_up_with_gray_circle);
        bitmapOpen = getBitmapWithTargetWidthHeight(bitmapOpen, labelHeight, labelHeight);
        bitmapClose = getBitmapWithTargetWidthHeight(bitmapClose, labelHeight, labelHeight);
        //其他
        rect = new Rect();
        list = new ArrayList<>();
        //默认数据
        if (BuildConfig.DEBUG) {//cwl 2023/10/18/018 13:41:只在预览时用到，正式使用时不加载
            list.add(new LabelBean(1, "Likes", "#FFEC8516"));
            list.add(new LabelBean(2, "Beautiful", "#FF3FBA80"));
            list.add(new LabelBean(3, "jewelry appraiser", "#FFE76158"));
            list.add(new LabelBean(4, "Friendly", "#FF7463E4"));
            list.add(new LabelBean(5, "Generous", "#FFBA4DEB"));
            list.add(new LabelBean(6, "Kindness", "#FF2A9BD6"));
            list.add(new LabelBean(7, "Voice nice", "#FF31c37c"));
            list.add(new LabelBean(8, "Likessssssss", "#FFEC8516"));
            list.add(new LabelBean(9, "Beautiful", "#FF3FBA80"));
            list.add(new LabelBean(10, "jewelry appraiser", "#FFE76158"));
            list.add(new LabelBean(11, "Friendly", "#FF7463E4"));
            list.add(new LabelBean(12, "Generous", "#FFBA4DEB"));
            list.add(new LabelBean(13, "Kindness", "#FF2A9BD6"));
            list.add(new LabelBean(14, "Voice nice", "#FF31c37c"));
            list.get(1).setSelected(true);
            setLabels(list, defaultShowRows, canSelect, onClickListener);
        }
    }

    /**
     * 开启动画
     */
    private void startAnim() {
        if (valueAnimator != null && valueAnimator.isRunning()) {
            valueAnimator.cancel();
            valueAnimator = null;
        }
        valueAnimator = ValueAnimator.ofFloat(0, labelHeight / 4);//cwl 2023/11/3/003 14:09:选中时，标签向四周放大移动的距离
        valueAnimator.addUpdateListener(animation -> {
            valueFactor = (float) animation.getAnimatedValue();
            handleDataWithAnim();
            invalidate();
        });
        valueAnimator.setDuration(ANIM_DURATION);
        valueAnimator.start();
    }

    /**
     * 生成新的Bitmap图片
     *
     * @return 所求
     */
    private Bitmap getBitmapWithTargetWidthHeight(Bitmap bitmap, float newWidth, float newHeight) {
        Matrix matrix = new Matrix();
        int width = bitmap.getWidth();//获取图片本身的宽
        int height = bitmap.getHeight();//获取图片本身的高
        float scaleRatioOfWidth = newWidth / (width > 0 ? width : newWidth);//宽度缩放比
        float scaleRatioOfHeight = newHeight / (height > 0 ? height : newHeight);//高度缩放比
        matrix.postScale(scaleRatioOfWidth, scaleRatioOfHeight);
        return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (bitmapOpen != null && !bitmapOpen.isRecycled()) {
            bitmapOpen.recycle();
            bitmapOpen = null;
        }
        if (bitmapClose != null && !bitmapClose.isRecycled()) {
            bitmapClose.recycle();
            bitmapClose = null;
        }
    }

    /**
     * 获取宽或者高
     *
     * @param measureSpec 测量单位
     * @param isWidSpec   是宽还是高
     * @return 所求
     */
    private int measure(int measureSpec, boolean isWidSpec) {
        int result;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result = isWidSpec ? viewWidth : viewHeight;
            if (mode == MeasureSpec.AT_MOST) result = Math.min(result, size);
        }
        return result;
    }

    /**
     * 转化长度单位
     *
     * @param dp dp长度
     * @return 对应的px长度
     */
    private float dpToPx(float dp) {
        float scale = getResources().getDisplayMetrics().density;
        return dp * scale;
    }
    //endregion

    public interface OnClickListener {
        void onClickItem(LabelBean labelBean);
    }
}
